import { Injectable, LoggerService as NestLoggerService } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import * as winston from 'winston'
import DailyRotateFile from 'winston-daily-rotate-file'
import { Request } from 'express'

/**
 * 日志级别枚举
 */
export enum LogLevel {
  ERROR = 'error',
  WARN = 'warn',
  INFO = 'info',
  HTTP = 'http',
  VERBOSE = 'verbose',
  DEBUG = 'debug',
  SILLY = 'silly'
}

/**
 * 日志上下文接口
 */
export interface LogContext {
  userId?: string
  sessionId?: string
  requestId?: string
  ip?: string
  userAgent?: string
  method?: string
  url?: string
  statusCode?: number
  responseTime?: number
  [key: string]: any
}

/**
 * 日志元数据接口
 */
export interface LogMeta {
  timestamp: string
  level: string
  message: string
  context?: LogContext
  stack?: string
  error?: Error
  [key: string]: any
}

@Injectable()
export class LoggerService implements NestLoggerService {
  private readonly logger: winston.Logger
  private readonly isDevelopment: boolean
  private readonly logLevel: string

  constructor(private readonly configService: ConfigService) {
    this.isDevelopment = this.configService.get('NODE_ENV') === 'development'
    this.logLevel = this.configService.get('LOG_LEVEL', 'info')

    this.logger = this.createLogger()
  }

  /**
   * 创建Winston日志器
   */
  private createLogger(): winston.Logger {
    const logDir = this.configService.get('LOG_DIR', 'logs')
    const maxSize = this.configService.get('LOG_MAX_SIZE', '20m')
    const maxFiles = this.configService.get('LOG_MAX_FILES', '14d')

    // 自定义日志格式
    const customFormat = winston.format.combine(
      winston.format.timestamp({
        format: 'YYYY-MM-DD HH:mm:ss.SSS'
      }),
      winston.format.errors({ stack: true }),
      winston.format.json(),
      winston.format.printf(info => {
        const { timestamp, level, message, context, stack, ...meta } = info

        const logEntry: LogMeta = {
          timestamp: String(timestamp),
          level: level.toUpperCase(),
          message: String(message)
        }

        if (context) {
          logEntry.context = context
        }

        if (stack) {
          logEntry.stack = String(stack)
        }

        if (Object.keys(meta).length > 0) {
          Object.assign(logEntry, meta)
        }

        return JSON.stringify(logEntry)
      })
    )

    // 控制台格式（开发环境）
    const consoleFormat = winston.format.combine(
      winston.format.colorize(),
      winston.format.timestamp({
        format: 'HH:mm:ss.SSS'
      }),
      winston.format.printf(info => {
        const { timestamp, level, message, context, stack } = info
        let output = `${timestamp} [${level}] ${message}`

        if (context) {
          const contextStr = Object.entries(context)
            .map(([key, value]) => `${key}=${value}`)
            .join(' ')
          output += ` | ${contextStr}`
        }

        if (stack) {
          output += `\n${stack}`
        }

        return output
      })
    )

    const transports: winston.transport[] = []

    // 控制台输出（开发环境）
    if (this.isDevelopment) {
      transports.push(
        new winston.transports.Console({
          format: consoleFormat,
          level: this.logLevel
        })
      )
    }

    // 错误日志文件
    transports.push(
      new DailyRotateFile({
        filename: `${logDir}/error-%DATE%.log`,
        datePattern: 'YYYY-MM-DD',
        level: 'error',
        format: customFormat,
        maxSize,
        maxFiles,
        zippedArchive: true
      })
    )

    // 组合日志文件
    transports.push(
      new DailyRotateFile({
        filename: `${logDir}/combined-%DATE%.log`,
        datePattern: 'YYYY-MM-DD',
        format: customFormat,
        maxSize,
        maxFiles,
        zippedArchive: true,
        level: this.logLevel
      })
    )

    // HTTP访问日志文件
    transports.push(
      new DailyRotateFile({
        filename: `${logDir}/access-%DATE%.log`,
        datePattern: 'YYYY-MM-DD',
        level: 'http',
        format: customFormat,
        maxSize,
        maxFiles,
        zippedArchive: true
      })
    )

    return winston.createLogger({
      level: this.logLevel,
      transports,
      exitOnError: false,
      // 处理未捕获的异常
      exceptionHandlers: [
        new DailyRotateFile({
          filename: `${logDir}/exceptions-%DATE%.log`,
          datePattern: 'YYYY-MM-DD',
          format: customFormat,
          maxSize,
          maxFiles,
          zippedArchive: true
        })
      ],
      // 处理未处理的Promise拒绝
      rejectionHandlers: [
        new DailyRotateFile({
          filename: `${logDir}/rejections-%DATE%.log`,
          datePattern: 'YYYY-MM-DD',
          format: customFormat,
          maxSize,
          maxFiles,
          zippedArchive: true
        })
      ]
    })
  }

  /**
   * 从请求对象提取上下文信息
   */
  private extractContextFromRequest(req: Request): LogContext {
    return {
      requestId: req.headers['x-request-id'] as string,
      ip: req.ip || req.connection.remoteAddress,
      userAgent: req.headers['user-agent'],
      method: req.method,
      url: req.originalUrl || req.url,
      userId: (req as any).user?.id,
      sessionId: (req as any).sessionID
    }
  }

  /**
   * 记录错误日志
   */
  error(message: string, error?: Error, context?: LogContext): void {
    this.logger.error(message, {
      context,
      stack: error?.stack,
      error: error
        ? {
            name: error.name,
            message: error.message
          }
        : undefined
    })
  }

  /**
   * 记录警告日志
   */
  warn(message: string, context?: LogContext): void {
    this.logger.warn(message, { context })
  }

  /**
   * 记录信息日志
   */
  log(message: string, context?: LogContext): void {
    this.logger.info(message, { context })
  }

  /**
   * 记录调试日志
   */
  debug(message: string, context?: LogContext): void {
    this.logger.debug(message, { context })
  }

  /**
   * 记录详细日志
   */
  verbose(message: string, context?: LogContext): void {
    this.logger.verbose(message, { context })
  }

  /**
   * 记录HTTP访问日志
   */
  http(message: string, context?: LogContext): void {
    this.logger.http(message, { context })
  }

  /**
   * 记录请求日志
   */
  logRequest(req: Request, message?: string): void {
    const context = this.extractContextFromRequest(req)
    const logMessage = message || `${req.method} ${req.originalUrl || req.url}`
    this.http(logMessage, context)
  }

  /**
   * 记录响应日志
   */
  logResponse(req: Request, statusCode: number, responseTime: number, message?: string): void {
    const context = {
      ...this.extractContextFromRequest(req),
      statusCode,
      responseTime
    }

    const logMessage = message || `${req.method} ${req.originalUrl || req.url} ${statusCode} - ${responseTime}ms`

    if (statusCode >= 400) {
      this.warn(logMessage, context)
    } else {
      this.http(logMessage, context)
    }
  }

  /**
   * 记录数据库操作日志
   */
  logDatabase(operation: string, table: string, duration?: number, context?: LogContext): void {
    const message = `Database ${operation} on ${table}${duration ? ` (${duration}ms)` : ''}`
    this.debug(message, context)
  }

  /**
   * 记录认证日志
   */
  logAuth(action: string, userId?: string, success: boolean = true, context?: LogContext): void {
    const message = `Auth ${action} ${success ? 'succeeded' : 'failed'}${userId ? ` for user ${userId}` : ''}`
    const logContext = { ...context, userId, authAction: action, success }

    if (success) {
      this.log(message, logContext)
    } else {
      this.warn(message, logContext)
    }
  }

  /**
   * 记录文件操作日志
   */
  logFile(operation: string, filename: string, size?: number, context?: LogContext): void {
    const message = `File ${operation}: ${filename}${size ? ` (${size} bytes)` : ''}`
    this.log(message, { ...context, fileOperation: operation, filename, size })
  }

  /**
   * 记录安全事件日志
   */
  logSecurity(event: string, severity: 'low' | 'medium' | 'high' | 'critical', context?: LogContext): void {
    const message = `Security event: ${event} (${severity})`
    const logContext = { ...context, securityEvent: event, severity }

    switch (severity) {
      case 'critical':
      case 'high':
        this.error(message, undefined, logContext)
        break
      case 'medium':
        this.warn(message, logContext)
        break
      default:
        this.log(message, logContext)
    }
  }

  /**
   * 记录性能日志
   */
  logPerformance(operation: string, duration: number, threshold?: number, context?: LogContext): void {
    const message = `Performance: ${operation} took ${duration}ms`
    const logContext = { ...context, operation, duration, threshold }

    if (threshold && duration > threshold) {
      this.warn(`Slow ${message}`, logContext)
    } else {
      this.debug(message, logContext)
    }
  }

  /**
   * 获取日志统计信息
   */
  async getLogStats(date?: string): Promise<any> {
    // 这里可以实现日志统计功能
    // 例如读取日志文件并分析
    return {
      date: date || new Date().toISOString().split('T')[0],
      totalLogs: 0,
      errorCount: 0,
      warnCount: 0,
      infoCount: 0
    }
  }

  /**
   * 清理旧日志文件
   */
  async cleanupLogs(daysToKeep: number = 30): Promise<void> {
    this.log(`Cleaning up logs older than ${daysToKeep} days`)
    // 这里可以实现日志清理逻辑
  }

  /**
   * 获取Winston日志器实例
   */
  getWinstonLogger(): winston.Logger {
    return this.logger
  }
}
